import * as fs from 'fs';
import * as path from 'path';

export interface FieldInfo {
  name: string;
  type: string;
  modifier: string; // public, protected, private, etc.
  lineNumber: number;
  fullDeclaration: string;
  isStatic?: boolean;
  isFinal?: boolean;
}

export interface EncapsulationResult {
  success: boolean;
  message: string;
  encapsulatedFields: Array<{
    fieldName: string;
    originalDeclaration: string;
    newDeclaration: string;
    getterMethod: string;
    setterMethod: string;
  }>;
  updatedReferences: Array<{
    filePath: string;
    lineNumber: number;
    oldAccess: string;
    newAccess: string;
  }>;
  refactorDetails?: string[];
  errors?: string[];
}

/**
 * 字段封装重构器 - 将public字段封装为private并生成getter/setter
 * 功能：识别public字段，生成private字段+getter/setter，更新所有字段访问
 */
export class FieldEncapsulationRefactor {

  async encapsulateFields(
    filePath: string,
    projectPath: string,
    includeProtected: boolean = false,
    generateSetters: boolean = true
  ): Promise<EncapsulationResult> {
    const result: EncapsulationResult = {
      success: false,
      message: '',
      encapsulatedFields: [],
      updatedReferences: [],
      refactorDetails: [],
      errors: []
    };

    try {
      console.error(`[FieldEncapsulationRefactor] 开始字段封装重构`);
      console.error(`[FieldEncapsulationRefactor] 源文件: ${filePath}`);
      console.error(`[FieldEncapsulationRefactor] 项目路径: ${projectPath}`);
      
      if (!fs.existsSync(filePath)) {
        result.errors?.push('源文件不存在');
        result.message = '源文件不存在';
        return result;
      }

      const sourceContent = fs.readFileSync(filePath, 'utf-8');
      const className = this.extractClassName(sourceContent);
      
      if (!className) {
        result.errors?.push('无法识别类名');
        result.message = '无法识别类名';
        return result;
      }

      // 查找需要封装的字段
      const fieldsToEncapsulate = this.findFieldsToEncapsulate(sourceContent, includeProtected);
      console.error(`[FieldEncapsulationRefactor] 找到 ${fieldsToEncapsulate.length} 个需要封装的字段`);

      if (fieldsToEncapsulate.length === 0) {
        result.success = true;
        result.message = '没有找到需要封装的字段';
        return result;
      }

      // 生成封装后的类内容
      let updatedContent = sourceContent;
      const encapsulatedFields: any[] = [];

      for (const field of fieldsToEncapsulate) {
        // 生成private字段声明
        const newFieldDeclaration = this.generatePrivateFieldDeclaration(field);
        
        // 生成getter方法
        const getterMethod = this.generateGetterMethod(field);
        
        // 生成setter方法（如果需要）
        let setterMethod = '';
        if (generateSetters && !field.isFinal) {
          setterMethod = this.generateSetterMethod(field);
        }

        // 替换字段声明
        updatedContent = updatedContent.replace(field.fullDeclaration, newFieldDeclaration);

        // 在类的末尾添加getter/setter方法
        updatedContent = this.addMethodsToClass(updatedContent, getterMethod, setterMethod);

        encapsulatedFields.push({
          fieldName: field.name,
          originalDeclaration: field.fullDeclaration,
          newDeclaration: newFieldDeclaration,
          getterMethod,
          setterMethod
        });

        result.refactorDetails?.push(`封装字段: ${field.name}`);
      }

      // 写入更新后的文件
      fs.writeFileSync(filePath, updatedContent, 'utf-8');

      // 查找并更新所有字段访问
      const references = await this.findFieldReferences(projectPath, className, fieldsToEncapsulate, filePath);
      console.error(`[FieldEncapsulationRefactor] 找到 ${references.length} 个字段引用`);

      for (const ref of references) {
        try {
          const updated = await this.updateFieldAccess(ref, fieldsToEncapsulate);
          if (updated) {
            result.updatedReferences.push(ref);
            result.refactorDetails?.push(`更新字段访问: ${ref.filePath}:${ref.lineNumber}`);
          }
        } catch (error) {
          result.errors?.push(`更新字段访问失败 ${ref.filePath}: ${error}`);
        }
      }

      result.encapsulatedFields = encapsulatedFields;
      result.success = true;
      result.message = `成功封装 ${fieldsToEncapsulate.length} 个字段`;

    } catch (error) {
      result.errors?.push(`字段封装重构失败: ${error}`);
      result.message = `字段封装重构失败: ${error}`;
      console.error(`[FieldEncapsulationRefactor] 错误:`, error);
    }

    return result;
  }

  private findFieldsToEncapsulate(content: string, includeProtected: boolean): FieldInfo[] {
    const fields: FieldInfo[] = [];
    const lines = content.split('\n');
    
    for (let i = 0; i < lines.length; i++) {
      const line = lines[i].trim();
      
      // 跳过注释和空行
      if (!line || line.startsWith('//') || line.startsWith('/*') || line.startsWith('*')) {
        continue;
      }

      // 匹配字段声明的正则表达式
      const fieldPattern = /^\s*(public|protected)\s+(?:(static)\s+)?(?:(final)\s+)?(\w+(?:<[^>]+>)?(?:\[\])*)\s+(\w+)(?:\s*=\s*[^;]+)?\s*;/;
      const match = line.match(fieldPattern);
      
      if (match) {
        const [fullMatch, modifier, staticKeyword, finalKeyword, type, name] = match;
        
        // 检查是否需要包含protected字段
        if (modifier === 'protected' && !includeProtected) {
          continue;
        }

        fields.push({
          name,
          type,
          modifier,
          lineNumber: i + 1,
          fullDeclaration: line,
          isStatic: !!staticKeyword,
          isFinal: !!finalKeyword
        });
      }
    }

    return fields;
  }

  private generatePrivateFieldDeclaration(field: FieldInfo): string {
    let declaration = '    private ';
    
    if (field.isStatic) {
      declaration += 'static ';
    }
    
    if (field.isFinal) {
      declaration += 'final ';
    }
    
    declaration += `${field.type} ${field.name}`;
    
    // 保留初始化值（如果有的话）
    const originalLine = field.fullDeclaration;
    const initMatch = originalLine.match(/=\s*([^;]+)/);
    if (initMatch) {
      declaration += ` = ${initMatch[1].trim()}`;
    }
    
    declaration += ';';
    return declaration;
  }

  private generateGetterMethod(field: FieldInfo): string {
    const capitalizedName = field.name.charAt(0).toUpperCase() + field.name.slice(1);
    const methodName = field.type.toLowerCase() === 'boolean' ? `is${capitalizedName}` : `get${capitalizedName}`;
    
    let method = '\n';
    method += `    public ${field.type} ${methodName}() {\n`;
    method += `        return ${field.name};\n`;
    method += '    }\n';
    
    return method;
  }

  private generateSetterMethod(field: FieldInfo): string {
    const capitalizedName = field.name.charAt(0).toUpperCase() + field.name.slice(1);
    
    let method = '\n';
    method += `    public void set${capitalizedName}(${field.type} ${field.name}) {\n`;
    method += `        this.${field.name} = ${field.name};\n`;
    method += '    }\n';
    
    return method;
  }

  private addMethodsToClass(content: string, getterMethod: string, setterMethod: string): string {
    // 找到类的最后一个右大括号
    const lastBraceIndex = content.lastIndexOf('}');
    if (lastBraceIndex === -1) {
      return content;
    }

    // 在最后一个大括号前插入方法
    const beforeBrace = content.substring(0, lastBraceIndex);
    const afterBrace = content.substring(lastBraceIndex);
    
    return beforeBrace + getterMethod + setterMethod + afterBrace;
  }

  private async findFieldReferences(
    projectPath: string,
    className: string,
    fields: FieldInfo[],
    excludeFilePath: string
  ): Promise<Array<{ filePath: string; lineNumber: number; fieldName: string; oldAccess: string; newAccess: string }>> {
    const references: Array<{ filePath: string; lineNumber: number; fieldName: string; oldAccess: string; newAccess: string }> = [];
    
    const searchDir = async (dirPath: string) => {
      if (!fs.existsSync(dirPath)) return;
      
      const entries = fs.readdirSync(dirPath, { withFileTypes: true });
      
      for (const entry of entries) {
        const fullPath = path.join(dirPath, entry.name);
        
        if (entry.isDirectory()) {
          if (!this.shouldSkipDirectory(entry.name)) {
            await searchDir(fullPath);
          }
        } else if (entry.isFile() && entry.name.endsWith('.java')) {
          const fileReferences = await this.findFieldReferencesInFile(fullPath, className, fields);
          references.push(...fileReferences);
        }
      }
    };
    
    await searchDir(projectPath);
    return references;
  }

  private async findFieldReferencesInFile(
    filePath: string,
    className: string,
    fields: FieldInfo[]
  ): Promise<Array<{ filePath: string; lineNumber: number; fieldName: string; oldAccess: string; newAccess: string }>> {
    const references: Array<{ filePath: string; lineNumber: number; fieldName: string; oldAccess: string; newAccess: string }> = [];
    
    try {
      const content = fs.readFileSync(filePath, 'utf-8');
      const lines = content.split('\n');
      
      for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        
        for (const field of fields) {
          // 查找字段访问模式
          const accessPatterns = [
            new RegExp(`\\b\\w+\\.${field.name}\\b`),        // object.field
            new RegExp(`\\bthis\\.${field.name}\\b`),        // this.field
            new RegExp(`\\b${className}\\.${field.name}\\b`) // ClassName.field (静态字段)
          ];
          
          for (const pattern of accessPatterns) {
            const match = line.match(pattern);
            if (match) {
              const oldAccess = match[0];
              const newAccess = this.generateNewFieldAccess(oldAccess, field);
              
              references.push({
                filePath,
                lineNumber: i + 1,
                fieldName: field.name,
                oldAccess,
                newAccess
              });
            }
          }
        }
      }
    } catch (error) {
      console.error(`[FieldEncapsulationRefactor] 读取文件失败: ${filePath}`, error);
    }
    
    return references;
  }

  private generateNewFieldAccess(oldAccess: string, field: FieldInfo): string {
    const capitalizedName = field.name.charAt(0).toUpperCase() + field.name.slice(1);
    const getterName = field.type.toLowerCase() === 'boolean' ? `is${capitalizedName}` : `get${capitalizedName}`;
    
    // 判断是否为赋值操作
    const objectPart = oldAccess.substring(0, oldAccess.lastIndexOf('.'));
    
    // 这里简化处理，实际应该分析上下文判断是读取还是写入
    return `${objectPart}.${getterName}()`;
  }

  private async updateFieldAccess(
    reference: { filePath: string; lineNumber: number; fieldName: string; oldAccess: string; newAccess: string },
    fields: FieldInfo[]
  ): Promise<boolean> {
    try {
      let content = fs.readFileSync(reference.filePath, 'utf-8');
      const originalContent = content;
      
      // 替换字段访问
      content = content.replace(reference.oldAccess, reference.newAccess);
      
      // 如果有变更，写回文件
      if (content !== originalContent) {
        fs.writeFileSync(reference.filePath, content, 'utf-8');
        console.error(`[FieldEncapsulationRefactor] 更新字段访问: ${reference.filePath}:${reference.lineNumber}`);
        return true;
      }
      
    } catch (error) {
      console.error(`[FieldEncapsulationRefactor] 更新字段访问失败: ${reference.filePath}`, error);
    }
    
    return false;
  }

  private shouldSkipDirectory(dirName: string): boolean {
    const skipDirs = [
      'node_modules', '.git', '.idea', '.vscode', 'target', 'build', 
      'dist', 'out', '.gradle', 'bin', 'logs', 'temp', 'tmp'
    ];
    return skipDirs.includes(dirName) || dirName.startsWith('.');
  }

  private extractClassName(content: string): string | null {
    const match = content.match(/(?:public\s+)?(?:class|interface|enum)\s+(\w+)/);
    return match ? match[1] : null;
  }
}